﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Compilex.BaseLibrary;

namespace Compilex.Automata
{
    /// <summary>
    /// Representa um estado em um autômato finito. Cada estado tem um nome, que deve
    /// ser único, e uma lista de transições. Esta classe implementa os operadores
    /// == e !=, além dos métodos Equals e GetHashCode.
    /// </summary>
    public class DFAState : IState<DFAState>
    {
        public String Name { get; set; }
        public bool IsAcceptState { get; set; }

        public SimpleList<ITransitionRule<DFAState>> Transitions { get; set; }

        public DFAState()
        {
            this.Name = "Anonymous state";
            this.IsAcceptState = false;
            this.Transitions = new SimpleList<ITransitionRule<DFAState>>();
        }

        public DFAState(String name)
        {
            this.Name = name;
            this.IsAcceptState = false;
            this.Transitions = new SimpleList<ITransitionRule<DFAState>>();
        }

        public DFAState(String name, bool isAcceptState)
        {
            this.Name = name;
            this.IsAcceptState = isAcceptState;
            this.Transitions = new SimpleList<ITransitionRule<DFAState>>();
        }

        public DFAState(String name, SimpleTransitionRule<DFAState>[] transitions)
        {
            this.Name = name;
            this.IsAcceptState = false;
            this.Transitions = new SimpleList<ITransitionRule<DFAState>>(transitions);
        }
        public DFAState(String name, bool isAcceptState, SimpleTransitionRule<DFAState>[] transitions)
        {
            this.Name = name;
            this.IsAcceptState = isAcceptState;
            this.Transitions = new SimpleList<ITransitionRule<DFAState>>(transitions);
        }

        /// <summary>
        /// Se houver uma transição para esta entrada, retorna o estado destino.
        /// Caso contrário, retorna null.
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public DFAState TryGetDestinationState(string input)
        {
            for (int i = 0; i < Transitions.Count; i++)
            {
                if (Transitions[i].MatchesInput(input))
                {
                    return Transitions[i].Destination;
                }
            }
            
            return null;
        }

        public void AddTransition(string input, DFAState destination)
        {
            for (int i = 0; i < Transitions.Count; i++)
            {
                if (Transitions[i].MatchesInput(input))
                {
                    throw new ArgumentException("Já existe uma transição neste" +
                    " estado para o caractere " + input);
                }
            }
            AddTransition(new SimpleTransitionRule<DFAState>(input, destination));
        }

        public void AddTransition(Predicate<string> predicate, DFAState Destination)
        {
            AddTransition(new PredicateTransitionRule<DFAState>(predicate, Destination));
        }

         public void AddTransition(char c, DFAState state)
        {
            AddTransition(c.ToString(), state);
        }

        public void AddTransition(ITransitionRule<DFAState> rule)
        {
            Transitions.Add(rule);
        }


        //public static bool operator ==(DFAState a, DFAState b)
        //{
        //    if (System.Object.ReferenceEquals(a, b))
        //    {
        //        return true;
        //    }

        //    // If one is null, but not both, return false.
        //    if (((object)a == null) || ((object)b == null))
        //    {
        //        return false;
        //    }
        //    return a.Name == b.Name;
        //}

        //public override bool Equals(object obj)
        //{
        //    if (obj is DFAState)
        //    {
        //        return this == (DFAState)obj;
        //    }
        //    else
        //    {
        //        return false;
        //    }
        //}

        //public override int GetHashCode()
        //{
        //    return Name.GetHashCode();
        //}

        //public static bool operator !=(DFAState a, DFAState b)
        //{
        //    return !(a == b);
        //}

        public override string ToString()
        {
            return Name;
        }
    }
}
